package gwtappcontainer.server.apis.insight;

import static gwtappcontainer.server.apis.insight.OfyService.ofy;
import gwtappcontainer.server.DatastoreNamespaces;
import gwtappcontainer.server.apis.APIException;
import gwtappcontainer.shared.apis.APIResponse.Status;
import gwtappcontainer.shared.apis.insight.Member;

import java.util.ArrayList;
import java.util.Collections;

import com.google.appengine.api.NamespaceManager;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.cmd.Query;

public class MemberRepository {	
	
	private final static String NAMESPACE = DatastoreNamespaces.INSIGHT;
	
	public static Member addMember(String email, String primaryCenter, String firstName,
			String middleName, String lastName, String homeAddress, String homePhone,
			String officeAddress, String officePhone) {
		
		email = email.toLowerCase();				
		
		NamespaceManager.set(NAMESPACE);
		MemberEntity entity = ofy().load().type(MemberEntity.class)
				.filter("email", email).first().get();
		
		if (null != entity) 
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a member with email [" + email + "]");
		
		entity = new MemberEntity();
		entity.email = email;
		if (firstName == null) firstName = "";
		entity.firstName = firstName;
		entity.middleName = middleName;
		entity.lastName = lastName;
		entity.homeAddress = homeAddress;
		entity.homePhone = homePhone;
		entity.officeAddress = officeAddress;
		entity.officePhone = officePhone;
		
		Key<CenterEntity> centerKey = CenterRepository.getKeyFromName(primaryCenter);
		if (null == centerKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Center [" + primaryCenter + "] does not exist");
		
		Ref<CenterEntity> centerRef = ofy().load().key(centerKey);
		
		entity.primaryCenter = centerRef;
		
		entity.centers.add(centerRef);		
						
		ofy().save().entity(entity).now();
		
		return entity.toProp();		
	}
	
	public static Member addCenterToMember(String email, String center) {
		email = email.toLowerCase();				
		
		NamespaceManager.set(NAMESPACE);
		MemberEntity memberEntity = ofy().load().type(MemberEntity.class)
				.filter("email", email).first().get();
		
		if (null == memberEntity) 
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"There is no member with email [" + email + "]");
		
		Key<CenterEntity> centerKey = CenterRepository.getKeyFromName(center);
		if (null == centerKey) 
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Center [" + center + "] does not exist");
		
		Ref<CenterEntity> centerRef = ofy().load().key(centerKey);
		
		memberEntity.centers.add(centerRef);
		ofy().save().entity(memberEntity).now();
		
		return memberEntity.toProp();
	}
	
	public static Member addUnlistedProgramToMember(String email, String programType,
			String venue, int month, int year, String teacher) {			
		
		MemberEntity memberEntity = getEntity(email);
		if (null == memberEntity)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST,
					"There is no member with email [" + email + "]");
		
		Key<ProgramTypeEntity> programTypeKey = ProgramTypeRepository
				.getKeyByName(programType);
		
		if (null == programTypeKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Program type [" + programType + "] is not valid");
		
		if (memberEntity.unlistedPrograms == null) {
			UnlistedProgramsEntity e = new UnlistedProgramsEntity();
			ofy().save().entity(e).now();
			memberEntity.unlistedPrograms = Ref.create(e);
			ofy().save().entity(memberEntity).now();
		}
		
		UnlistedProgramsEmbeddedEntity embedded = 
				new UnlistedProgramsEmbeddedEntity();
		embedded.programType = programType;
		embedded.venue = venue;
		embedded.month = month;
		embedded.year = year;		
		embedded.teacher = teacher;
		
		memberEntity.unlistedPrograms.get().programs.add(embedded);
		ofy().save().entity(memberEntity.unlistedPrograms.get()).now();
		
		
		Ref<ProgramTypeEntity> programTypeRef = ofy().load().key(programTypeKey);
				
		NamespaceManager.set(NAMESPACE);
		memberEntity.programTypes.add(programTypeRef);
		ofy().save().entity(memberEntity).now();
		
		return memberEntity.toProp();
	}
	
	public static Member get(String email) {
		MemberEntity entity = getEntity(email);
		
		if (entity == null)
			return null;
		
		return entity.toProp();
	}
	
	static MemberEntity getEntity(String email) {
		email = email.toLowerCase();				
		
		NamespaceManager.set(NAMESPACE);
		MemberEntity entity = ofy().load().type(MemberEntity.class)
				.filter("email", email).first().get();
		
		if (entity == null)
			return null;
		
		return entity;
	}
	
	public static ArrayList<Member> getByCenter(String center) {
		Key<CenterEntity> centerKey = CenterRepository.getKeyFromName(center);
		
		if (null == centerKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
			"Center [" + center + "] does not exist");
		
		NamespaceManager.set(NAMESPACE);
		Query<MemberEntity> query = ofy().load().type(MemberEntity.class)
				.filter("centers", centerKey);
								
		ArrayList<Member> props = new ArrayList<>();
		for (MemberEntity e : query) {
			props.add(e.toProp());
		}
		
		Collections.sort(props);
		
		return props;
	}			
	
	public static ArrayList<Member> getByProgramType(String programType) {
		Key<ProgramTypeEntity> programTypeKey = 
				ProgramTypeRepository.getKeyByName(programType);
		
		if (null == programTypeKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
			"Program type [" + programType + "] is not valid");
		
		NamespaceManager.set(NAMESPACE);
		Query<MemberEntity> query = ofy().load().type(MemberEntity.class)
				.filter("programTypes", programTypeKey);
								
		ArrayList<Member> props = new ArrayList<>();
		for (MemberEntity e : query) {
			props.add(e.toProp());
		}
		
		Collections.sort(props);

		return props;
	}	
	
	public static ArrayList<Member> getByCenterAndProgramType(String programType, 
			String center) {
		
		Key<ProgramTypeEntity> programTypeKey = 
				ProgramTypeRepository.getKeyByName(programType);		
		if (null == programTypeKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
			"Program type [" + programType + "] is not valid");
		
		Key<CenterEntity> centerKey = CenterRepository.getKeyFromName(center);
		if (null == centerKey)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
			"Center [" + center + "] is not valid");
		
		NamespaceManager.set(NAMESPACE);
		Query<MemberEntity> query = ofy().load().type(MemberEntity.class)
				.filter("programTypes", programTypeKey)
				.filter("centers", centerKey);
								
		ArrayList<Member> props = new ArrayList<>();
		for (MemberEntity e : query) {
			props.add(e.toProp());
		}
		
		Collections.sort(props);

		return props;
	}	
}
